﻿using NUnit.Framework.Internal;
using SLAssetSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace SLBehaviourSystem
{
    public class BehaviourSystem : Singleton<BehaviourSystem>, IInitable
    {
        private Dictionary<int, List<BehaviourTree>> trees = new Dictionary<int, List<BehaviourTree>>();

        Dictionary<int,BehaviourTreeJsonData> treeConfigs = new Dictionary<int, BehaviourTreeJsonData>();

        public void Init()
        {
            CsvData data = AssetSystem.Inst.LoadResAsset<CsvData>(AssetPaths.ConfigsPath, "BehaviourTree", AssetType.CSV);
            BehaviourTreeInfos infos = new BehaviourTreeInfos();
            infos.InitData(data);
            Dictionary<int,BehaviourTreeInfo> infoDict= infos.GetInfos();
            foreach (var info in infoDict)
            {
                JsonData jsonData = AssetSystem.Inst.LoadResAsset<JsonData>(AssetPaths.BehaviourTreeConfigPath, info.Value.Name, AssetType.Json);
                BehaviourTreeJsonData treeJsonData = jsonData.GetData<BehaviourTreeJsonData>();
                treeConfigs.Add(info.Key, treeJsonData);
            }
            Debug.Log(treeConfigs.Count);
        }

        public void Tick()
        {
            //foreach (var tree in trees)
            //{
            //    for (int i = 0; i < tree.Value.Count; i++)
            //    {
            //        if (tree.Value[i].Agent.IsEnabled)
            //        {
            //            tree.Value[i].Excute();
            //        }
            //    }
            //}
        }

        public BehaviourTree CreateTreeTest(int type, BehaviourAgent agent)
        {
            BehaviourTree tree = new BehaviourTree();
            tree.Agent = agent;
            if (trees.ContainsKey(type))
            {
                trees[type].Add(tree);
            }
            else
            {
                trees.Add(type, new List<BehaviourTree>() { tree });
            }
            return tree;
        }

        public BehaviourTree CreateTree(int type, BehaviourAgent agent)
        {
            Dictionary<int, BehaviourNodeBase> nodes = new Dictionary<int, BehaviourNodeBase>();
            BehaviourTree tree = new BehaviourTree();
            BehaviourTreeJsonData data = treeConfigs[type];
            tree.Tree = data;
            tree.Agent = agent;
            var componentDict = BehaviourComponentConfig.ComponentDict;
            for (int i = data.Nodes.Count - 1; i >= 0; i--)
            {
                BehaviourTreeNodeJsonData nodeData = data.Nodes[i];
                Type nodeType = BehaviourNodeConfig.NodeDict[nodeData.NodeType][nodeData.RuntimeNodeType];
                BehaviourNodeBase node = Activator.CreateInstance(nodeType) as BehaviourNodeBase;
                node.Agent = agent;
                node.InteruptType = nodeData.InterrupteType;
                node.ExcuteType = nodeData.ExcuteType;
                nodes.Add(nodeData.Id, node);

                DataContainer behaviourData = new DataContainer();
                for (int j = 0; j < nodeData.Datas.Count; j++)
                {
                    behaviourData.AddData(nodeData.Datas[j].Key, nodeData.Datas[j].Value);
                }
                node.Id = nodeData.Id;
                node.BehaviourData = behaviourData;

                if (componentDict.ContainsKey(nodeData.NodeType))
                {
                    if (componentDict[nodeData.NodeType].ContainsKey(nodeData.RuntimeComponentType))
                    {
                        if (!agent.Components.ContainsKey(nodeData.RuntimeComponentType))
                        {
                            Type componentType = componentDict[nodeData.NodeType][nodeData.RuntimeComponentType];
                            BehaviourComponent component = agent.gameObject.AddComponent(componentType) as BehaviourComponent;
                            agent.Components.Add(nodeData.RuntimeComponentType, component);
                        }
                        node.Component = agent.Components[nodeData.RuntimeComponentType];
                    }
                }

                for (int j = 0; j < nodeData.ChildIds.Count; j++)
                {
                    node.AddChild(nodes[nodeData.ChildIds[j]]);
                }
            }

            foreach (var component in agent.Components)
            {
                component.Value.Init(agent);
            }
            tree.NodeDict = nodes;
            tree.AddChild(nodes[0]);

            return tree;
        }

        public Dictionary<int, List<BehaviourTree>> GetTrees()
        {
            return trees;
        }
    }
}
